package
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.Point;
	import flash.text.*;
	import flash.text.TextField;
	import flash.ui.Mouse;
	import flash.utils.getTimer;
	
	/** This class displays the shapes for reward.*/
	public class ShapeGarden extends MovieClip
	{
		public static const BACKGROUND_COLOR:uint = 0xEEFFEE;
		public var xml:XML;
		public var duration:int;		
		public var WIDTH:Number, HEIGHT:Number, TITLE_HEIGHT:Number, COLOR_PICKER_HEIGHT:Number;
		// private objects
		private var cursor:Sprite=null;
		private var polygonPanel:Sprite;
		private var nextb:MyButton;
		private var parentPolygons:Array, polygons:Array;
		private var tools:GardenTools;
		private var colorPicker:ColorPicker;
		private var titleTField:TextField;
		private var countdownClock:CountdownClock;
		// private vars
		private var isFirst:Boolean, isFinal:Boolean, isFinalFinal:Boolean;
		private var unit:Number;// relative to 1000;
		private var timestamp:int;
		private var current_tool:String = "color";
		private var cursor_color:uint = 0xFFFFFF;
		// for pen tool
		private var penShape:Shape = null; // the currrent shape being drawn
		private var penPoints:Array; // the current set of points generated by the pen
		private var firstPoint:Sprite = null;
		
		public function ShapeGarden(WIDTH:Number, HEIGHT:Number, TITLE_HEIGHT:Number, xml:XML, duration:int, isFirst:Boolean=false, isFinal:Boolean=false, isFinalFinal:Boolean=false)
		{
			this.xml = xml;
			this.WIDTH = WIDTH;
			this.HEIGHT = HEIGHT;
			this.TITLE_HEIGHT = TITLE_HEIGHT;
			this.COLOR_PICKER_HEIGHT = HEIGHT / 4;
			this.duration = duration*1000;
			this.isFinal = isFinal;
			this.isFinalFinal = isFinalFinal;
			this.isFirst = isFirst;
			this.addEventListener(Event.ADDED, handleAdded);
		}
		private function handleAdded(event:Event):void
		{
			unit = stage.width/1000;
			
			this.removeEventListener(Event.ADDED, handleAdded);
			this.graphics.beginFill(BACKGROUND_COLOR);
			this.graphics.drawRect(0,0,WIDTH, HEIGHT);
			this.graphics.endFill();
			
			this.graphics.beginFill(0x008800);
			this.graphics.drawRect(0, 0, WIDTH, TITLE_HEIGHT);
			this.graphics.endFill();
			// draw title
			titleTField = new TextField();
			titleTField.mouseEnabled = false;
			titleTField.selectable = false;
			titleTField.defaultTextFormat = new TextFormat("arial", 30, 0xEEFFEE);
			if (isFirst)
			{
				titleTField.text = "Welcome to your shape garden.";
			} else if (isFinalFinal)
			{
				titleTField.text = "Congratulations, you've completed all of the gardens for this lesson!!!";
			} else if (isFinal)
			{
				titleTField.text = "Congratulations, you've completed this garden!!!";
			} else 
			{
				titleTField.text = "Great, you've added more shapes to your garden!";
			}
			titleTField.autoSize = "left";
			titleTField.x = (this.width-titleTField.width)/2;
			titleTField.y = (TITLE_HEIGHT - titleTField.height)/2;
			this.addChild(titleTField);
			
			// add the garden tools
			tools = new GardenTools(this.width/8, COLOR_PICKER_HEIGHT, COLOR_PICKER_HEIGHT/7);
			this.addChild(tools);
			tools.addEventListener (Event.COMPLETE , handleNewTool);
			tools.y = this.HEIGHT - tools.height;
			// add the color picker
			colorPicker = new ColorPicker(0, COLOR_PICKER_HEIGHT);
			this.addChild(colorPicker);
			colorPicker.addEventListener (Event.COMPLETE, handleColorPick);
			colorPicker.x = this.width/8;
			colorPicker.y = this.HEIGHT - colorPicker.height;
			
			
			// go through each "child shape" and create a parent shape (they grew up, I guess)
			polygonPanel = new Sprite();
			polygonPanel.graphics.beginFill(0xDDFFDD);
			polygonPanel.graphics.drawRect(0, 0, WIDTH, HEIGHT - TITLE_HEIGHT - colorPicker.height);
			polygonPanel.y = TITLE_HEIGHT;
			this.addChild(polygonPanel);
			
			parentPolygons = new Array();
			polygons = new Array();
			//trace(xml..child_shape);
			for each (cn in xml..obstacle)
			{
				//trace(cn);
				points = new Array();
				for each (p in cn..point)
				{
					points.push(new Point(p.@x, p.@y));
				}
				var o:Polygon = new Polygon(points, uint(cn.@color), 1); 
				o.addEventListener(MouseEvent.CLICK, handleClickObstacle);
				polygons.push(o);		
				polygonPanel.addChild(o);
			}
			for each (var cn:XML in xml..child_shape)
			{
				//trace(cn);
				var points:Array = new Array();
				for each (var p:XML in cn..point)
				{
					points.push(new Point(p.@x, p.@y));
				}
				var pp:ParentPolygon = new ParentPolygon(0,0,cn.@type,cn.@id,ShapeProductionTask.TYPES,points,uint(cn.@color));
				//pp.x = pp.width + (polygonPanel.width-2*pp.width)*Math.random();
				//pp.y = pp.height+(polygonPanel.height-2*pp.height)*Math.random();
				pp.addEventListener(MouseEvent.CLICK, handleClickPolygon);
				polygonPanel.addChild(pp);
				parentPolygons.push(pp);
				polygons.push(pp);
				pp.scale = .25;
				
			}
			this.placePolygonsWithoutCollisions(unit*100, unit*100, polygonPanel.width-unit*100, polygonPanel.height-unit*100);
			
			
			for each (pp in parentPolygons)
			{
				pp.neighbors = polygons;
				pp.moveRandomly(polygonPanel.height, .1+Math.random(), 1+Math.random());
			}
			// add next button
			var nextText:String;
			if (isFinalFinal){ nextText = "I'm done.";}
			else {nextText = "Next shape";}
			nextb = new MyButton((this.width-(colorPicker.x + colorPicker.width))/2, colorPicker.height/4, 20, 10, 10, 0x446644, nextText, 0xDDFFDD, 0x224422, nextText, 0xDDFFDD, 0x446644, nextText, 0xDDFFDD); 
			nextb.x = colorPicker.x + colorPicker.width+((this.width-colorPicker.x-colorPicker.width) - nextb.width)/2;
			nextb.y = this.height - nextb.height - 10;
			nextb.addEventListener(Event.COMPLETE, handleNextButton);
			this.addChild(nextb);
			
			// setup for pen
			penShape = new Shape();
			polygonPanel.addChild(penShape);
			penPoints = new Array();
			// add cursor
			drawCursor();
			
			Mouse.hide();
			// add countdown clock
			if (duration > 0)
			{
				//countdownClock = new CountdownClock((this.width-(colorPicker.x + colorPicker.width))/2, colorPicker.height/4, duration);
				countdownClock = new CountdownClock(nextb.width, nextb.height, duration);
				countdownClock.x = nextb.x;
				countdownClock.y = nextb.y - countdownClock.height - 10;
				this.addChild(countdownClock);
				countdownClock.start();
			}			
			
			timestamp = flash.utils.getTimer();
			this.addEventListener(Event.ENTER_FRAME, handleFrame);
		}
		private function drawCursor():void
		{
			if (cursor==null)
			{
				cursor = new Sprite();
				cursor.mouseEnabled = false;
				this.addChild(cursor);
			} else
			{
				cursor.graphics.clear();
			}
			if (this.current_tool == "color")
			{
				cursor.graphics.lineStyle(unit, 0xAA8866);
				if (cursor_color == 0xFFFFFF){ cursor.graphics.beginFill(cursor_color,.5); }
				else { cursor.graphics.beginFill(cursor_color); }
				// draw dropper
				cursor.graphics.moveTo(unit*5/4, 0);
				cursor.graphics.lineTo(unit*10/4, -5*unit);
				cursor.graphics.lineTo(unit*10/4, -30*unit);
				cursor.graphics.lineTo(-unit*10/4, -30*unit);
				cursor.graphics.lineTo(-unit*10/4, -5*unit);
				cursor.graphics.lineTo(-unit*10/8, 0);
				cursor.graphics.lineStyle(unit*10/8, 0xAA8866, .5);
				cursor.graphics.lineTo(unit*10/8, 0);
				cursor.graphics.endFill();
				cursor.graphics.beginFill(0xAAAAAA);
				cursor.graphics.drawCircle(0, -30*unit, unit*10/3);
				cursor.graphics.endFill();
				cursor.rotation = 30;
			} else if (this.current_tool == "pen")
			{
				cursor.graphics.beginFill(0xAAAAAA);
				cursor.graphics.drawEllipse(-unit*5, -unit*5, unit*10, unit*10);
				cursor.graphics.endFill();
				var pwidth:Number = unit*4;
				var pheight:Number = unit*20;
				// draw pen
				cursor.graphics.lineStyle(pwidth/8,0x444444);
				cursor.graphics.beginFill(0x888888);
				cursor.graphics.moveTo(0,0);
				cursor.graphics.lineTo(pwidth/2,-pwidth);
				cursor.graphics.lineTo(-pwidth/2,-pwidth)
				cursor.graphics.lineTo(0,0);
				cursor.graphics.beginFill(0x8888FF);
				cursor.graphics.moveTo(pwidth/2,-pwidth);
				cursor.graphics.lineTo(pwidth/2,-pheight);
				cursor.graphics.lineTo(-pwidth/2,-pheight);
				cursor.graphics.lineTo(-pwidth/2,-pwidth)
				cursor.graphics.endFill();
				// handle
				cursor.graphics.beginFill(0x888888);
				cursor.graphics.drawEllipse(-pwidth/2,-pheight-pwidth/4,pwidth,pwidth/2);
				cursor.graphics.endFill();
				cursor.rotation=30;	
			} else if (this.current_tool == "delete")
			{
				cursor.graphics.clear();
				cursor.graphics.lineStyle(2,0x000000);
				cursor.graphics.moveTo(-unit*5*Math.sqrt(2)/2,-unit*5*Math.sqrt(2)/2);
				cursor.graphics.lineTo(unit*5*Math.sqrt(2)/2,unit*5*Math.sqrt(2)/2);
				cursor.graphics.moveTo(unit*5*Math.sqrt(2)/2,-unit*5*Math.sqrt(2)/2);
				cursor.graphics.lineTo(-unit*5*Math.sqrt(2)/2,unit*5*Math.sqrt(2)/2);
			}
		}
		/** Called in response to a new tool selection by the garden tools */
		private function handleNewTool (event:Event):void
		{
			var previous_tool:String = current_tool;
			this.current_tool = tools.modeName;
			drawCursor();
			// clear any shapes being currently drawn by the pen
			if (penShape != null && penShape.parent == polygonPanel)
			{
				penShape.graphics.clear();
				penPoints = new Array();
				if (firstPoint != null)
				{
					firstPoint.removeEventListener(MouseEvent.CLICK, handleClickFirstPoint);
					polygonPanel.removeChild(firstPoint);
					firstPoint = null;
				}
			} else
			{
				penShape = new Shape();
				polygonPanel.addChild(penShape);
			}
			polygonPanel.removeEventListener(MouseEvent.CLICK, handleClickEmptyPanel);
			polygonPanel.removeEventListener(MouseEvent.RIGHT_CLICK, handleRightClickEmptyPanel);
			if (current_tool == "color")
			{
				this.colorPicker.alpha = 1;
			} else if (current_tool == "pen")
			{
				polygonPanel.addEventListener(MouseEvent.CLICK, handleClickEmptyPanel);
				polygonPanel.addEventListener(MouseEvent.RIGHT_CLICK, handleRightClickEmptyPanel);
				this.colorPicker.alpha = 0;
			} else if (current_tool == "delete")
			{
				this.colorPicker.alpha = 0;
			}
		}
		
////////////////////////////////  parent parentPolygons coloring /////////////////////////////////////////////////		
		private function handleClickPolygon (event:MouseEvent):void
		{
			if (current_tool == "color")
			{
				if (cursor_color != 0xFFFFFF)
				{
					ParentPolygon(event.currentTarget).color = cursor_color;
				}
			}
		}
		private function handleColorPick (event:Event):void
		{
			if (current_tool == "color")
			{
				cursor_color = colorPicker.color;
				drawCursor();
			}
		}
/////////////////////////////////  pen //////////////////////////////////////////////////////////////////////
		private function handleClickEmptyPanel (event:MouseEvent):void
		{
			if (event.target == event.currentTarget)
			{
				var p:Point = new Point (polygonPanel.mouseX, polygonPanel.mouseY);
				penPoints.push(p);
				if (penPoints.length == 1)
				{
					penShape.graphics.moveTo(p.x, p.y);
					// draw first point
					firstPoint = new Sprite ();
					firstPoint.x = p.x;
					firstPoint.y = p.y;
					firstPoint.graphics.beginFill(0x666666);
					firstPoint.graphics.drawCircle(0, 0, 4*unit);
					firstPoint.graphics.endFill();
					firstPoint.addEventListener(MouseEvent.CLICK, handleClickFirstPoint);
					polygonPanel.addChild(firstPoint);
				} else
				{
					penShape.graphics.lineStyle(4*unit, 0x888888);
					penShape.graphics.lineTo(p.x, p.y);
				}
				penShape.graphics.lineStyle(0, 0x888888);
				penShape.graphics.beginFill(0x888888);
				penShape.graphics.drawCircle(p.x, p.y, 4*unit);
				penShape.graphics.endFill();
			}
		}
		private function handleRightClickEmptyPanel (event:MouseEvent):void
		{
			// clear any shapes being currently drawn by the pen
			if (penShape != null && penShape.parent == polygonPanel)
			{
				penShape.graphics.clear();
				penPoints = new Array();
				if (firstPoint != null)
				{
					firstPoint.removeEventListener(MouseEvent.CLICK, handleClickFirstPoint);
					polygonPanel.removeChild(firstPoint);
					firstPoint = null;
				}
			}
		}
		private function handleClickFirstPoint (event:MouseEvent):void
		{
			firstPoint.removeEventListener(MouseEvent.CLICK, handleClickFirstPoint);
			polygonPanel.removeChild(firstPoint);
			firstPoint = null;
			penShape.graphics.clear();
			var clearOfParents:Boolean = true;
			// cycle through all shapes and make sure that none are within bounds of this obstacle
			var o:Polygon = new Polygon(penPoints, 0xAAAAAA, 1); 
			polygonPanel.addChildAt(o, 0);
			for each (var pp:ParentPolygon in parentPolygons)
			{
				if (pp.hitTestPolygon(o, true)) {clearOfParents = false; break;}
			}
			if (clearOfParents)
			{
				o.addEventListener(MouseEvent.CLICK, handleClickObstacle);
				polygons.push(o);		
				// run through parentPolygons and adjust neighbors
				for each (var ps:ParentPolygon in this.parentPolygons)
				{
					ps.neighbors = polygons;
				}
			} else
			{
				polygonPanel.removeChild(o);				
			}
			penPoints = new Array();
		}
//////////////////////////////// obstacle /////////////////////////////////////////////////////////////////////		
		private function handleClickObstacle (event:MouseEvent):void
		{
			if (current_tool == "color")
			{
				if (cursor_color != 0xFFFFFF)
				{
					Polygon(event.currentTarget).color = cursor_color;
				}
			} else if (current_tool == "delete")
			{
				event.currentTarget.removeEventListener (MouseEvent.CLICK, handleClickObstacle);
				polygonPanel.removeChild(Polygon(event.currentTarget));
				polygons.splice(polygons.indexOf(Polygon(event.currentTarget)),1);
				for each (var ps:ParentPolygon in this.parentPolygons)
				{
					ps.neighbors = polygons;
				}
			}
		}
//////////////////////////////// frame /////////////////////////////////////////////////////////////////////		
		private function handleFrame (event:Event):void
		{
			Mouse.hide();
			cursor.x = this.mouseX;
			cursor.y = this.mouseY;
			if (duration > 0)
			{
				if (flash.utils.getTimer() - timestamp >= duration)
				{
					complete();
				}
			}
		}
		private function handleNextButton (event:Event):void
		{
			complete();
		}
		/** Remove and stop parentPolygons, update xml for color, dispatch complete event */
		private function complete():void
		{
			this.removeEventListener(Event.COMPLETE, handleNextButton);
			if (penShape != null && penShape.parent == polygonPanel)
			{
				penShape.graphics.clear();
				penPoints = new Array();
				if (firstPoint != null)
				{
					firstPoint.removeEventListener(MouseEvent.CLICK, handleClickFirstPoint);
					polygonPanel.removeChild(firstPoint);
					firstPoint = null;
				}
			} 
			polygonPanel.removeEventListener(MouseEvent.CLICK, handleClickEmptyPanel);
			polygonPanel.removeEventListener(MouseEvent.RIGHT_CLICK, handleRightClickEmptyPanel);
			
			// remove all obstacles
			if (xml..obstacles[0].child("obstacle").length() > 0)
			{
				var onode:XML = new XML();
				onode = <obstacles>
						</obstacles>;
				xml.replace("obstacles", onode);
			}
			
			for each (var p:Polygon in polygons)
			{
				var node:XML, pnode:XML;
				// is this an obstacle
				if (p.type == "polygon")
				{
					
					node = new XML();
					node = <obstacle> </obstacle>;
					node.@color = p.color;
					for each (var point:Point in p.points)
					{
						pnode = new XML();
						pnode = <point> </point>;
						pnode.@x = point.x;
						pnode.@y = point.y;
						node.appendChild(pnode);
					}
					xml..obstacles[0].appendChild(node);
					polygonPanel.removeChild(p);
				} else // or a moving parent
				{
					var pp:ParentPolygon = ParentPolygon(p);
					pp.stopMoving();
					// find xml node with matching id
					pnode = xml..child_shape.(@id==pp.id)[0];
					pnode.@color = pp.color;	
					polygonPanel.removeChild(pp);
				}
				
			}
			this.removeEventListener(Event.ENTER_FRAME, handleFrame);
			Mouse.show();
			this.dispatchEvent(new Event(Event.COMPLETE));
		}
		/** Compares current display object to all objects on obstacle list */
		private function placePolygonsWithoutCollisions (minX:Number, minY:Number, maxX:Number, maxY:Number):void
		{
			var maxTries:uint = 100;
			var placedObstacles:Array = new Array();
			for each (var o:Polygon in parentPolygons)
			{
				var tries:uint = 0;
				do 
				{
					var conflict:Boolean = false;
					o.x = minX + Math.random() * (maxX - minX);
					o.y = minY + Math.random() * (maxY - minY);
					for each (var p:Polygon in polygons)
					{
						if (o != p)
						{
							if (o.hitTestPolygon(p) && tries < maxTries)
							{
								//trace(o, p, o.hitTestPolygon(p), tries, maxTries, o.x, o.y);
								conflict = true;
								break;
							}
						}
					}
					tries++;
				} while (conflict)	
			}
			//polygons = placedObstacles;
		}
		private function handleRemoved (event:Event):void
		{
			this.removeEventListener(Event.REMOVED, handleRemoved);			
		}
	}
}